Shared Memory

AI
gemma-4-31b
작성자
익명
작성일
2026.08.12
조회수
9
버전
v1

Shared Memory (공유 메모리)

1. 개요

공유 메모리(Shared Memory)란 여러 프로세스가 동일한 메모리 영역에 접근하여 데이터를 읽고 쓸 수 있도록 설정된 프로세스 간 통신(IPC, Inter-Process Communication) 메커니즘이다.

일반적으로 운영체제는 프로세스 간의 메모리 격리를 통해 보안과 안정성을 유지하지만, 공유 메모리는 특정 영역을 예외적으로 공유함으로써 데이터 복사 과정 없이 매우 빠른 속도로 정보를 교환할 수 있게 한다. 이는 파이프(Pipe)나 메시지 큐(Message Queue)와 같이 커널을 통해 데이터를 전달하는 방식과 달리, 한 번 설정되면 커널의 개입 없이 사용자 공간에서 직접 메모리에 접근한다는 점에서 차별화된다.

2. 장점과 단점

장점

  • 최고의 성능: 데이터 복사(Copy) 과정이 없으므로 IPC 방식 중 전송 속도가 가장 빠르다.
  • 대용량 데이터 효율성: 대규모 데이터를 여러 프로세스가 공유할 때 메모리 낭비를 최소화한다.

단점

  • 동기화 복잡성: 개발자가 직접 세마포어 등을 이용해 동기화를 구현해야 하며, 실수 시 데드락(Deadlock)이나 데이터 오염이 발생한다.
  • 관리 책임: 프로세스 종료 후에도 메모리가 남을 수 있어 명시적인 자원 회수 로직이 필수적이다.

3. 동작 원리 및 구조

공유 메모리는 가상 메모리 관리 체계의 페이지 테이블(Page Table) 매핑 원리를 이용한다. 각 프로세스는 자신만의 가상 주소 공간을 가지지만, 운영체제는 서로 다른 프로세스의 가상 주소를 물리 메모리의 동일한 프레임(Frame)에 매핑함으로써 공유 영역을 생성한다. 이때 각 프로세스에서 접근하는 가상 주소(Virtual Address)는 서로 다를 수 있지만, 물리 주소(Physical Address)는 동일하다.

메모리 접근 방식 비교

구분 일반적인 메모리 접근 (Isolated) 공유 메모리 접근 (Shared)
주소 공간 프로세스별로 완전히 독립된 가상 주소 할당 서로 다른 가상 주소가 동일한 물리 주소를 가리킴
데이터 전달 커널을 통한 복사 (User $\rightarrow$ Kernel $\rightarrow$ User) 직접 접근 (User $\rightarrow$ Shared Memory $\rightarrow$ User)
접근 권한 자신의 메모리 영역 외 접근 시 Segmentation Fault 발생 허가된 공유 영역에 대해 읽기/쓰기 권한 공유
속도 컨텍스트 스위칭 및 데이터 복사 비용 발생 메모리 참조 속도와 동일 (매우 빠름)

4. 주요 구현 방식

유닉스 계열 시스템에서는 크게 두 가지 표준 구현 방식이 사용된다.

4.1 System V Shared Memory

초기 유닉스 표준으로, 정수 형태의 키(Key)를 사용하여 공유 메모리 식별자를 생성한다. - shmget(): 공유 메모리 세그먼트를 생성하거나 식별자를 얻음. - shmat(): 생성된 세그먼트를 프로세스의 주소 공간에 연결(Attach). - shmdt(): 연결을 해제(Detach). - shmctl(): 세그먼트 제어 및 삭제.

4.2 POSIX Shared Memory

파일 시스템 기반의 인터페이스를 제공하며, 경로 이름(Path name)을 사용하여 더 직관적으로 관리한다. - shm_open(): 공유 메모리 객체를 생성하거나 연다. (가상 파일 생성) - ftruncate(): 공유 메모리의 크기를 설정한다. - <a href="/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/API/mmap" class="wiki-link">mmap</a>(): 파일 디스크립터를 프로세스의 메모리 주소 공간에 매핑한다. - munmap(): 매핑을 해제한다. - shm_unlink(): 공유 메모리 객체 이름을 제거한다.

C/C++ 구현 예시 (POSIX 기준)

#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main() {
    const char* name = "/my_shm"; // 공유 메모리 이름
    const int SIZE = 4096;        // 크기

    // 1. 공유 메모리 객체 생성
    int shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
    ftruncate(shm_fd, SIZE);

    // 2. 프로세스 주소 공간에 매핑
    void* ptr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);

    // 3. 데이터 쓰기
    const char* message = "Hello, Shared Memory!";
    // snprintf를 사용하여 버퍼 오버플로우 방지
    snprintf((char*)ptr, SIZE, "%s", message);

    printf("Data written to memory: %s\n", (char*)ptr);

    // 4. 정리 및 해제
    munmap(ptr, SIZE);
    close(shm_fd);
    shm_unlink(name);

    return 0;
}
주의: 위 예제는 단일 프로세스 내 동작을 보여주며, 실제 IPC 구현 시에는 프로세스 간 동기화 메커니즘(세마포어 등)이 반드시 추가되어야 합니다.

5. OS별 구현 차이

공유 메모리는 운영체제의 메모리 관리 방식에 따라 구현 세부 사항이 다르다.

  • Linux/Unix: 위에서 언급한 POSIX 및 System V 표준을 따르며, /dev/shm과 같은 가상 파일 시스템(tmpfs)을 통해 메모리 맵핑을 관리한다.
  • Windows: '파일 매핑(File Mapping)' 개념을 사용한다. CreateFileMapping 함수로 공유 메모리 객체를 생성하고, MapViewOfFile 함수를 통해 프로세스 주소 공간에 연결한다. 이름이 지정된 공유 메모리(Named Shared Memory)를 통해 프로세스 간 식별이 가능하다.

6. 동기화 문제와 해결 방안

공유 메모리는 커널이 데이터 접근을 제어하지 않으므로, 여러 프로세스가 동시에 쓰기 작업을 수행할 때 경쟁 상태(Race Condition)가 발생하여 데이터 무결성이 파괴될 수 있다. 이를 방지하기 위해 반드시 동기화 도구를 함께 사용해야 한다.

동기화 도구 비교

도구 작동 방식 특징 적합한 사례
뮤텍스 (Mutex) 상호 배제(Mutual Exclusion) 잠금 한 번에 하나의 프로세스만 접근 가능 단순한 임계 영역 보호
세마포어 (Semaphore) 카운터 기반의 신호 체계 지정된 개수의 프로세스 접근 허용 가능 생산자-소비자 패턴, 자원 개수 제한
스핀락 (Spinlock) 락을 얻을 때까지 루프를 돌며 대기 컨텍스트 스위칭 비용이 없으나 CPU 점유율 높음 매우 짧은 시간 동안의 락 유지 시
조건 변수 (Condition Variable) 특정 조건이 충족될 때까지 대기 이벤트 기반의 프로세스 깨움 가능 복잡한 상태 변화 알림

동기화 도구 사용 예시

  • 뮤텍스: 공유 메모리에 기록 중인 프로세스가 있을 때, 다른 프로세스가 접근하지 못하도록 잠금(Lock)을 걸어 데이터 오염을 방지한다.
  • 세마포어: 공유 메모리를 큐(Queue)처럼 사용할 때, '데이터가 들어있는 슬롯의 개수'를 세마포어로 관리하여 소비 프로세스가 데이터가 있을 때만 읽어가도록 제어한다.
  • 스핀락: 멀티코어 환경에서 아주 짧은 데이터를 업데이트할 때, 프로세스를 휴면 상태로 전환하는 비용보다 잠시 기다리는 비용이 적을 때 사용한다.
  • 조건 변수: 프로세스 A가 공유 메모리에 특정 계산 결과를 기록한 후, 대기 중이던 프로세스 B에게 "데이터 준비 완료" 신호를 보내 즉시 처리하게 한다.

7. 메모리 누수 방지 및 해제 방법

공유 메모리는 프로세스가 종료되어도 커널 내에 상주하는 영속성(Persistence)을 가진다. 따라서 명시적으로 해제하지 않으면 시스템 메모리가 낭비되는 메모리 누수가 발생한다.

  1. 명시적 해제:
  2. POSIX: shm_unlink()를 호출하여 이름 기반 객체를 제거해야 한다.
  3. System V: shmctl(shmid, IPC_RMID, NULL)을 통해 세그먼트를 삭제해야 한다.
  4. 참조 횟수 관리: munmap이나 shmdt는 현재 프로세스의 연결만 끊는 것이며, 실제 메모리 삭제는 모든 프로세스가 연결을 끊고 삭제 명령이 내려졌을 때 수행된다.
  5. 명령어 도구 활용 (Linux):
  6. ipcs -m: 현재 생성된 공유 메모리 세그먼트 목록 확인.
  7. ipcrm -m [shmid]: 특정 식별자의 공유 메모리 강제 삭제.

8. 활용 사례

  • 고성능 데이터베이스 엔진: MySQL, PostgreSQL 등의 버퍼 풀(Buffer Pool)은 디스크에서 읽어온 데이터를 공유 메모리에 올려 여러 쿼리 프로세스가 빠르게 접근하도록 한다.
  • 실시간 비디오/오디오 스트리밍: 고해상도 프레임 데이터를 캡처 프로세스에서 처리 프로세스로 전달할 때 복사 비용을 줄이기 위해 사용한다.
  • 대규모 데이터 분석 시스템: Apache Plasma와 같이 여러 언어(Python, C++, Java)로 작성된 프로세스들이 거대한 데이터프레임을 공유하여 분석하는 환경에서 활용된다.
  • 운영체제 커널과 유저 공간 통신: 일부 고성능 드라이버는 링 버퍼(Ring Buffer) 형태의 공유 메모리를 통해 커널과 데이터를 주고받는다.
AI 생성 콘텐츠 안내

이 문서는 AI 모델(gemma-4-31b)에 의해 생성된 콘텐츠입니다.

주의사항: AI가 생성한 내용은 부정확하거나 편향된 정보를 포함할 수 있습니다. 중요한 결정을 내리기 전에 반드시 신뢰할 수 있는 출처를 통해 정보를 확인하시기 바랍니다.

이 AI 생성 콘텐츠가 도움이 되었나요?